//
//  Agora Streaming Kit
//
//  Created by ShengQiang Liu in 2020-02.
//  Copyright (c) 2020 Agora IO. All rights reserved.
//
#pragma once

#include "AgoraMediaBase.h"
#include "NGIAgoraRtmpConnection.h"
#include "NGIAgoraRtmpLocalUser.h"
#include "api2/internal/video_node_i.h"
#include "engine_adapter/audio/audio_node_interface.h"
#include "engine_adapter/video/video_node_interface.h"
#include "facilities/tools/rtc_callback.h"
#include "main/core/audio/audio_send_stream.h"
#include "main/core/video/video_send_stream.h"
#include "rtmp_sender.h"

namespace rtc {
class TaskQueue;
}
namespace webrtc {
class VideoEncoderFactory;
}

namespace agora {
namespace rtc {
class RtmpConnectionImpl;
class VideoNodeRtmpNetworkSink;

class RtmpLocalUserImpl : public IRtmpLocalUser {
  friend class AudioSourceProxy;
  friend class VideoSourceProxy;

 public:
  struct Config {
    RtmpConnectionImpl* rtmp_connnection;
    RtmpStreamingAudioConfiguration audio_config;
    RtmpStreamingVideoConfiguration video_config;
  };

 public:
  explicit RtmpLocalUserImpl(const Config& config);
  ~RtmpLocalUserImpl();

  // IRtmpLocalUser interfaces
  int setAudioStreamConfiguration(const RtmpStreamingAudioConfiguration& config) override;
  int setVideoStreamConfiguration(const RtmpStreamingVideoConfiguration& config) override;

  int adjustRecordingSignalVolume(int volume) override;
  int getRecordingSignalVolume(int32_t* volume) override;
  int setAudioEnabled(bool enabled) override;

  void adjustVideoBitrate(VideoBitrateAdjustType type) override;
  int setVideoEnabled(bool enabled) override;

  int publishAudio(agora_refptr<rtc::ILocalAudioTrack> audioTrack) override;
  int unpublishAudio(agora_refptr<rtc::ILocalAudioTrack> audioTrack) override;
  int publishMediaPlayerAudio(agora_refptr<rtc::ILocalAudioTrack> audioTrack,
                              int32_t playerId) override;
  int unpublishMediaPlayerAudio(agora_refptr<rtc::ILocalAudioTrack> audioTrack,
                                int32_t playerId) override;
  int publishVideo(agora_refptr<rtc::ILocalVideoTrack> videoTrack) override;
  int unpublishVideo(agora_refptr<rtc::ILocalVideoTrack> videoTrack) override;
  int registerRtmpUserObserver(IRtmpLocalUserObserver* observer,
                               void (*safeDeleter)(IRtmpLocalUserObserver*) = NULL) override;
  int unregisteRtmpUserObserver(IRtmpLocalUserObserver* observer) override;
  int registerAudioFrameObserver(media::base::IAudioFrameObserver* observer) override;
  void unregisterAudioFrameObserver(media::base::IAudioFrameObserver* observer) override;
  int registerVideoFrameObserver(media::base::IVideoFrameObserver* observer) override;
  void unregisterVideoFrameObserver(media::base::IVideoFrameObserver* observer) override;

 private:
  void initialize();
  std::unique_ptr<AudioSendStream::Config> createAudioSendStreamConfig(
      const RtmpStreamingAudioConfiguration& audioConfig);
  void createEncoderTaskQueueIfNeeded();
  void notifyAudioFrame(media::base::AudioPcmFrame* audioFrame);
  std::unique_ptr<VideoSendStream::Config> createVideoSendStreamConfig(
      const RtmpStreamingVideoConfiguration& video_config);
  void notifyVideoFrame(const webrtc::VideoFrame& video_frame);

 private:
  // This is owned externally and is expected to live beyond the life of this object.
  RtmpConnectionImpl* rtmp_connection_;
  utils::RtcAsyncCallback<IRtmpLocalUserObserver>::Type rtmp_user_observers_;

  utils::RtcSyncCallback<media::base::IAudioFrameObserver>::Type audio_frame_observers_;

  RtmpStreamingAudioConfiguration audio_config_;
  bool is_audio_published_;

  agora_refptr<rtc::ILocalAudioTrack> audio_track_;

  std::shared_ptr<AudioNodeBase> audio_rtmp_network_sink_;

  std::unique_ptr<AudioSendStream> audio_send_stream_;
  agora_refptr<IAudioSinkBase> audio_source_;
  std::unique_ptr<::rtc::TaskQueue> task_queue_;

  RtmpStreamingVideoConfiguration video_config_;
  bool is_video_published_;

  agora_refptr<rtc::ILocalVideoTrack> video_track_;

  std::shared_ptr<VideoNodeRtmpNetworkSink> video_rtmp_network_sink_;

  std::shared_ptr<webrtc::VideoEncoderFactory> video_encoder_factory_;
  std::shared_ptr<VideoSendStream> video_send_stream_;
  agora_refptr<IVideoRendererEx> video_source_;
  std::shared_ptr<VideoNodeFrame> video_frame_forward_;

  utils::RtcSyncCallback<media::base::IVideoFrameObserver>::Type video_frame_observers_;
};

}  // namespace rtc
}  // namespace agora
